package com.zhz.springmvc.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.RequestMapping;
import com.zhz.springmvc.annotation.ResponseBody;
import com.zhz.springmvc.context.WebApplicationContext;
import com.zhz.springmvc.handler.HandlerMapping;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author ：zhz
 * @date ：Created in 2021/01/03
 * @version: V1.0
 * @slogan: 天下风云出我辈，一入代码岁月催
 * @description: 前端控制器
 **/
public class DispatcherServlet extends HttpServlet {

    //指定SpringMvc容器
    private WebApplicationContext webApplicationContext;
    //创建集合，用于存放映射关系、映射地址与控制器.方法，用于发送请求直接从该集合中进行匹配
    List<HandlerMapping> handList = new ArrayList<>();

    @Override
    public void init() throws ServletException {
        //1、从web.xml中获得加载初始化参数contextConfigLocation的值classpath:springmvc.xml
        String configLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
        //2、创建SpringMVC容器
        webApplicationContext = new WebApplicationContext(configLocation);

        //3、进行初始化操作
        webApplicationContext.onRefresh();

        //4、初始化请求映射关系   /findUser   ===》控制器.方法
        initHandlerMapping();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //进行请求分发处理
        doDispatcher(request, response);
    }


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    /**
     * 初始化请求映射关系(获取链接地址0
     */
    private void initHandlerMapping() {
        //遍历map， key存放bean的名字   value存放bean实例
        for (Map.Entry<String, Object> entry : webApplicationContext.iocMap.entrySet()) {
            //获得bean的class类型
            Class<?> clazz = entry.getValue().getClass();
            if (clazz.isAnnotationPresent(Controller.class)) {
                //获取bean中所有的方法，为这些方法建立映射关系
                Method[] methods = clazz.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        //获取注解中的值
                        String url = requestMapping.value();
                        //建立映射地址，与控制器 方法
                        HandlerMapping handlerMapping = new HandlerMapping(url, entry.getValue(), method);
                        handList.add(handlerMapping);
                    }
                }
            }
        }
    }

    /**
     * 进行请求分发处理
     *
     * @param request
     * @param response
     */
    private void doDispatcher(HttpServletRequest request, HttpServletResponse response) {
        try {
            //根据用户的请求地址（/listUsers）查找Controller
            HandlerMapping handlerMapping = getHandler(request);

            if (handlerMapping == null) {
                response.getWriter().print("<h1>404 NOT  FOUND!</h1>");
            } else {
                //调用处理方法之前 进行参数的注入

                //调用目标方法---》获得方法的返回值类型
                Object result = handlerMapping.getMethod().invoke(handlerMapping.getController());
                if (result instanceof String){
                    //跳转到JSP中
                    String viewName = result.toString();
                    //forward:/success.jsp重定向
                    if (viewName.contains(":")){
                        String viewType=viewName.split(":")[0];//也就是forward或者redirect
                        String viewPage=viewName.split(":")[1];//跳转的页面
                        if (viewType.equals("forward")){//请求转发
                            request.getRequestDispatcher(viewPage).forward(request,response);
                        }else{//重定向
                            response.sendRedirect(viewPage);
                        }
                    }else{
                        //默认请求转发
                        request.getRequestDispatcher(viewName).forward(request,response);
                    }
                }else{
                    //返回JSON格式数据
                    Method method=handlerMapping.getMethod();
                    if (method.isAnnotationPresent(ResponseBody.class)){
                        //将返回值转换成 json格式数据
                        ObjectMapper objectMapper = new ObjectMapper();
                        String json = objectMapper.writeValueAsString(result);
                        response.setContentType("text/html;charset=utf-8");
                        PrintWriter writer= response.getWriter();
                        writer.print(json);
                        writer.flush();
                        writer.close();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (ServletException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据用户请求查找对应的Handler======>获取请求对应的handler(也就是从handList中取出)
     *
     * @param request
     * @return
     */
    private HandlerMapping getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        for (HandlerMapping handlerMapping : handList) {
            //从容器的Handle取出URL  和  用户的请求地址进行匹配，找到满足条件的Handler(controller)
            if (handlerMapping.getUrl().equals(requestURI)) {
                return handlerMapping;
            }
        }
        return null;
    }

}
